package com.mx.restful.fullurl;

import com.intellij.codeInsight.codeVision.CodeVisionAnchorKind;
import com.intellij.codeInsight.codeVision.CodeVisionEntry;
import com.intellij.codeInsight.codeVision.CodeVisionRelativeOrdering;
import com.intellij.codeInsight.codeVision.ui.model.ClickableTextCodeVisionEntry;
import com.intellij.codeInsight.codeVision.ui.model.CodeVisionPredefinedActionEntry;
import com.intellij.codeInsight.hints.codeVision.DaemonBoundCodeVisionProvider;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.ide.CopyPasteManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.mx.restful.annotation.HttpMethodAnnotation;
import com.mx.restful.service.Notify;
import com.mx.restful.utils.RestUtil;
import kotlin.Pair;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;

import java.awt.datatransfer.StringSelection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static icons.MxIcons.SPRING;
import static icons.MxIcons.YMP;

public class FullUrlProvider implements DaemonBoundCodeVisionProvider {

    public static final String GROUP_ID = "com.mx.restful";
    public static final String ID = "fullUrl";
    public static final String NAME = "复制完整的URL";

    public static final List<String> MAPPING_ANNOTATION_MAPPING = Arrays.asList(
            HttpMethodAnnotation.SPRING_REQUEST_MAPPING.getQualifiedName(),
            HttpMethodAnnotation.SPRING_GET_MAPPING.getQualifiedName(),
            HttpMethodAnnotation.SPRING_POST_MAPPING.getQualifiedName(),
            HttpMethodAnnotation.SPRING_PUT_MAPPING.getQualifiedName(),
            HttpMethodAnnotation.SPRING_DELETE_MAPPING.getQualifiedName(),
            HttpMethodAnnotation.SPRING_PATCH_MAPPING.getQualifiedName()
    );


    @NotNull
    @Override
    public CodeVisionAnchorKind getDefaultAnchor() {
        // 默认展示在元素的顶部
        return CodeVisionAnchorKind.Right;
    }

    @NotNull
    @Override
    public String getId() {
        return ID;
    }

    @NotNull
    @Override
    public String getGroupId() {
        return GROUP_ID;
    }

    @Nls
    @NotNull
    @Override
    public String getName() {
        return NAME;
    }

    @NotNull
    @Override
    public List<CodeVisionRelativeOrdering> getRelativeOrderings() {
        // 设置展示顺序为第一个
        return Collections.singletonList(CodeVisionRelativeOrdering.CodeVisionRelativeOrderingFirst.INSTANCE);
    }

    private static String getAnnotationUrl(PsiAnnotation psiAnnotation) {
        String url = "";
        PsiAnnotationMemberValue psiAnnotationMemberValue = psiAnnotation.findAttributeValue("value");
        if (psiAnnotationMemberValue != null) {
            url = psiAnnotationMemberValue.getText();
        }
        return url;
    }

    private PsiAnnotation getSpringAnnotation(PsiMethod psiMethod) {
        PsiAnnotation psiAnnotation = null;
        for (String annotation : MAPPING_ANNOTATION_MAPPING) {
            psiAnnotation = psiMethod.getAnnotation(annotation);
            if (psiAnnotation != null) {
                break;
            }
        }
        return psiAnnotation;
    }

    private String fixPackAndClassUrl(String url) {
        url = url.replace("\"", "");
        if (!url.endsWith("/")) {
            url = url + "/";
        }
        if (url.startsWith("/")) {
            url = url.substring(1);
        }
        return url;
    }

    private String fixUrl(String url) {
        url = url.replace("\"", "");
        if (url.endsWith("/")) {
            url = url.substring(0,url.length()-1);
        }
        if (url.startsWith("/")) {
            url = url.substring(1);
        }
        return url;
    }


    private kotlin.Pair<TextRange, CodeVisionEntry> getYmpMappingUrl(Project project, PsiMethod psiMethod, String packageUrl, String classUrl) {
        PsiAnnotation psiAnnotation = psiMethod.getAnnotation(HttpMethodAnnotation.REQUEST_MAPPING.getQualifiedName());
        if (psiAnnotation == null) {
            return null;
        }
        String url = getAnnotationUrl(psiAnnotation);
        if (StringUtils.isBlank(url)) {
            return null;
        }
        TextRange textRange = psiAnnotation.getTextRange();
        packageUrl = fixPackAndClassUrl(packageUrl);
        classUrl = fixPackAndClassUrl(classUrl);
        url = fixUrl(url);
        String resultUrl = url;
        if (StringUtils.isNotBlank(classUrl)) {
            resultUrl = classUrl + resultUrl;
        }
        if (StringUtils.isNotBlank(packageUrl)) {
            resultUrl = packageUrl + resultUrl;
        }
        String finalText = resultUrl;
        ClickableTextCodeVisionEntry codeVisionEntry = new ClickableTextCodeVisionEntry("复制完整的URL", getId(), (event, editor) -> {
            CopyPasteManager copyPasteManager = CopyPasteManager.getInstance();
            StringSelection stringSelection = new StringSelection(finalText);
            copyPasteManager.setContents(stringSelection);
            Notify.getInstance(project).info("URL复制成功");
            return null;
        }, YMP, "", "", Collections.emptyList());

        return new kotlin.Pair<>(textRange, codeVisionEntry);
    }



    private kotlin.Pair<TextRange, CodeVisionEntry> getSpringMappingUrl(Project project, PsiMethod psiMethod, String classUrl) {
        PsiAnnotation psiAnnotation = getSpringAnnotation(psiMethod);
        if (psiAnnotation == null) {
            return null;
        }
        String url = getAnnotationUrl(psiAnnotation);
        if (StringUtils.isBlank(url)) {
            return null;
        }
        TextRange textRange = psiAnnotation.getTextRange();
        classUrl = fixPackAndClassUrl(classUrl);
        url = fixUrl(url);
        String resultUrl = url;
        if (StringUtils.isNotBlank(classUrl)) {
            resultUrl = classUrl + resultUrl;
        }
        String finalText = resultUrl;
        ClickableTextCodeVisionEntry codeVisionEntry = new ClickableTextCodeVisionEntry("复制完整的URL", getId(), (event, editor) -> {
            CopyPasteManager copyPasteManager = CopyPasteManager.getInstance();
            StringSelection stringSelection = new StringSelection(finalText);
            copyPasteManager.setContents(stringSelection);
            Notify.getInstance(project).info("URL复制成功");
            return null;
        }, SPRING, "", "", Collections.emptyList());

        return new kotlin.Pair<>(textRange, codeVisionEntry);
    }


    // 设置展示场景：java文件的方法上展示
    @NotNull
    @Override
    public List<Pair<TextRange, CodeVisionEntry>> computeForEditor(@NotNull Editor editor, @NotNull PsiFile file) {
        Project project = editor.getProject();
        List<Pair<TextRange, CodeVisionEntry>> lenses = new ArrayList<>();
        if (project == null) {
            return lenses;
        }
        PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
        if (!(psiFile instanceof PsiJavaFile)) {
            return lenses;
        }
        PsiJavaFile psiJavaFile = (PsiJavaFile) psiFile;
        PsiClass[] classes = psiJavaFile.getClasses();
        if (classes.length == 0) {
            return lenses;
        }

        PsiPackage psiPackage = JavaPsiFacade.getInstance(project).findPackage(psiJavaFile.getPackageName());
        String packageUrl = "";
        if (psiPackage != null) {
            PsiAnnotation packageAnnotation = psiPackage.getAnnotation(HttpMethodAnnotation.REQUEST_MAPPING.getQualifiedName());
            if (packageAnnotation != null) {
                packageUrl = getAnnotationUrl(packageAnnotation);
            }
        }

        PsiClass psiClass = classes[0];
        boolean isYmp = false;
        PsiAnnotation classAnnotation = psiClass.getAnnotation(HttpMethodAnnotation.REQUEST_MAPPING.getQualifiedName());
        if (classAnnotation == null) {
            classAnnotation = psiClass.getAnnotation(HttpMethodAnnotation.SPRING_REQUEST_MAPPING.getQualifiedName());
        }
        if (classAnnotation == null) {
            return lenses;
        }
        if (classAnnotation.hasQualifiedName(HttpMethodAnnotation.REQUEST_MAPPING.getQualifiedName())) {
            isYmp = true;
        }
        String classUrl = getAnnotationUrl(classAnnotation);
        PsiMethod[] methods = psiClass.getMethods();
        for (PsiMethod method : methods) {
            kotlin.Pair<TextRange, CodeVisionEntry> pair;
            if (isYmp) {
                pair = getYmpMappingUrl(project, method, packageUrl, classUrl);
            } else {
                pair = getSpringMappingUrl(project, method, classUrl);
            }
            if(pair != null) {
                lenses.add(pair);
            }
        }
        return lenses;
    }

    @NotNull
    @Override
    @Deprecated
    public List<Pair<TextRange, CodeVisionEntry>> computeForEditor(@NotNull Editor editor) {
        // 过时方法，不用实现
        return Collections.emptyList();
    }

    // Inlay被点击后的处理逻辑
    @Override
    public void handleClick(@NotNull Editor editor, @NotNull TextRange textRange, @NotNull CodeVisionEntry entry) {
        if (entry instanceof CodeVisionPredefinedActionEntry) {
            ((CodeVisionPredefinedActionEntry) entry).onClick(editor);
        }
    }
}
